-- ========================================================
-- @File	: lib.lua
-- @Brief	: 通用工具库
-- @Author	: Leo Zhao
-- @Date	: 2017-11-06
-- ========================================================

-- 调用，防止unpack中断
function Call(f, v)
	if type(f) ~= 'function' then
		error('Call #1 must be function!');
	end

	local bArray, nCount = IsArray(v, false);
	if not bArray then
		return f(v);
	else
		if nCount == 0 then
			return f(v);
		elseif nCount == 1 then
			return f(v[1]);
		elseif nCount == 2 then
			return f(v[1], v[2]);
		elseif nCount == 3 then
			return f(v[1], v[2], v[3]);
		elseif nCount == 4 then
			return f(v[1], v[2], v[3], v[4]);
		elseif nCount == 5 then
			return f(v[1], v[2], v[3], v[4], v[5]);
		elseif nCount == 6 then
			return f(v[1], v[2], v[3], v[4], v[5], v[6]);
		elseif nCount == 7 then
			return f(v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
		elseif nCount == 8 then
			return f(v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]);
		elseif nCount == 9 then
			return f(v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9]);
		else
			error('Too many parameters for Call');
		end
	end
end

-- 判断是否是Array表
function IsArray(tb, bStrict)
	if type(tb) ~= 'table' then return false, 1 end;

	local nMaxIdx = 0;

	for k, v in pairs(tb) do
		if type(k) ~= 'number' then
			return false, 1;
		else
			nMaxIdx = math.max(nMaxIdx, k);
		end
	end

	if bStrict then
		for i = 1, nMaxIdx do
			if not tb[nMaxIdx] then return false, nMaxIdx end;
		end
	end

	return true, nMaxIdx;
end

-- 复制
function Copy(v)
	if type(v) ~= 'table' then return v end;

	local tb = {};

	for key, value in pairs(v) do
		if type(value) ~= 'table' then
			tb[key] = value;
		else
			tb[key] = Copy(value);
		end
	end

	return tb;
end

-- 合并Array
function Concat(tbHead, tbTail)
	local bHeadOk, nHead = IsArray(tbHead, true);
	local bTailOk, nTail = IsArray(tbTail, true);

	if not bHeadOk then
		error('Concat head is not an array table');
	elseif not bTailOk then
		error('Concat tail is not an array table');
	else
		local tbRet = Copy(tbHead);

		for i = 1, nTail do
			tbRet[nHead + i] = Copy(tbTail[i]);
		end

		return tbRet;
	end
end

-- 合并Map
function Merge(tbHigh, tbLow)
	if type(tbHigh) ~= 'table' or type(tbLow) ~= 'table' then
		error('Merge must be tables.');
	end

	local tb = Copy(tbHigh);

	for k, v in pairs(tbLow) do
		if not tb[k] then tb[k] = Copy(v) end;
	end

	return tb;
end

-- 洗牌
function Shuffle(tb)
	local bOk, nCount = IsArray(tb, true);
	if not bOk then
		error('Shuffle must on array tables.');
	end

	for i = 1, nCount - 1 do
		local j = math.random(i, nCount);
		tb[j], tb[i] = tb[i], tb[j];
	end
end

-- 运行代码（string to value）
function Eval(s)
	return assert(load('return ' .. s))();
end

-- 日期时间转时间截，YYYYmmdd[HH[MM[SS]]]
function ParseTime(s)
	if not s or not tonumber(s) then
		error('#1 must be datetime string YYYYmmdd[HH[MM[SS]]] like 20160101, 201601010200 etc.');
	end

	local l = string.len(s);
	if l < 8 then error('#1 must at least YYYYmmdd') end;

	local tb	= {
		year	= tonumber(string.sub(s, 1, 4)),
		month	= tonumber(string.sub(s, 5, 6)),
		day		= tonumber(string.sub(s, 7, 8)),
		hour	= 0,
		min		= 0,
		sec		= 0,
	};

	if l >= 10 then tb.hour = tonumber(string.sub(s, 9, 10)) end;
	if l >= 12 then tb.min = tonumber(string.sub(s, 11, 12)) end;
	if l >= 14 then tb.sec = tonumber(string.sub(s, 13, 14)) end;

	return os.time(tb);
end

-- 继承
function Inherit(tbBase)
	local tb = { super = tbBase };
	setmetatable(tb, { __index = function(tb, key) return tb.super[key] end });
	return tb;
end

-- 输出
function Dump(v)
	print('------------ Dump start -------------');
	print(type(v) == 'table' and json.encode(v) or v);
	print('------------ Dump End ---------------');
end

math.randomseed(os.time());